import { LibraryKodyRule } from '@/config/types/kodyRules.type';
import {
    IKodyRule,
    kodyRuleSchema,
} from '@/core/domain/kodyRules/interfaces/kodyRules.interface';
import { UncategorizedComment } from '@/core/infrastructure/adapters/services/codeBase/types/commentAnalysis.type';
import z from 'zod';

export const kodyRulesGeneratorSchema = z.object({
    rules: z.array(
        kodyRuleSchema.partial().extend({
            tags: z.array(z.string()).optional(),
        }),
    ),
});

export const prompt_KodyRulesGeneratorSystem = () => `
You are a professional code reviewer, you are great at identifying common patterns. Whenever you receive a list of code review suggestions you are able to identify common patterns and formulate new rules and guidelines for future reviews.

You will receive a list of suggestions with the following format:
[
    {
        id: string, unique identifier,
        body: string, content of the suggestion,
        language: string, programming language of the suggestion
    }
]

You will also receive a list of pre-made rules and guidelines from a rule library, with the format of the following example:
[
    {
        "uuid": "55a0284b-eb7f-40ae-8b8c-db3dc66e8e0a",
        "title": "Avoid equality operators in loop termination conditions",
        "rule": "Check if loops use equality operators (== or !=) in termination conditions. These can lead to infinite loops if the condition is never met exactly. Instead, use relational operators like < or > for safer loop termination.",
        "severity": "Critical",
        "tags": [ "cwe", "maintainability", "security" ],
        "examples": [
            {
                "snippet": "for (var i = 1; i <= 10; i += 2)  // Compliant\n{\n  //...\n}",
                "isCorrect": false
            },
            {
                "snippet": "for (var i = 1; i != 10; i += 2)  // Noncompliant. Infinite; i goes from 9 straight to 11.\n{\n  //...\n}",
                "isCorrect": true
            }
        ]
    }
]

You must then analyze each and every suggestion, once you've analyzed them all you will generate a list of at most 12 of the most impactful rules and guidelines for future reviews.
The rules must be impactful to the specific suggestions you received, they must be related to the suggestions you received. The goal is that the rules you generate will help prevent the same mistakes from happening in the future.
Whenever possible you should use one of the pre-existing rules, copying all the fields exactly as they are.

If you can't find a pre-made rule that fits, you must create a new rule. Your rule must have the same format as the pre-existing ones, except for the 'uuid' field.
Any rule generated by you, not copied from the pre-existing rules, must NOT have a 'uuid' field.
Each rule you create must have a title, the rule itself and two examples, each example is a small snippet of code generated by you, one of the examples must show a piece of code following the rule and the other must showcase a snippet of code breaking the rule.
After, you must give the rule a severity level, it must be either Low, Medium, High or Critical.
For example, if you see many suggestions that suggest using the 'async await' syntax in javascript rather than Promises and the 'then' syntax, then you should generate a new rule that encourages that behaviour.

Any rule you generate must be strictly related to code review suggestions, it must not be a general programming rule or meta rules.
For example, do not create rules about how to name files, how to structure a project, how best to do a pull request or how to write a commit message.

All rules must be related to the suggestions or comments you received.

All rules MUST be related to the language of the suggestion.

At the end your output must be only a json, you should not output any other text other than the list.
It should have the following format:
{
    "rules": [
        ...pre-existing rules,
        ...new rules
    ]
}

Your output must be surrounded by \`\`\`json\`\`\` tags.
`;

export const prompt_KodyRulesGeneratorUser = (payload: {
    comments: UncategorizedComment[];
    rules: LibraryKodyRule[];
}) => `
comments:

[
${payload.comments
    .map(
        (comment) => `
    {
        "id": "${comment.id}",
        "body": "${comment.body}",
        "language": "${comment.language ?? 'unknown'}"
    },
`,
    )
    .join('')}
]


rules:

[
${payload.rules
    .map(
        (rule) => `
    {
        "uuid": "${rule.uuid}",
        "title": "${rule.title}",
        "rule": "${rule.rule}",
        "severity": "${rule.severity}",
        "tags": "${rule.tags}",
        "examples": [
        ${rule.examples.map(
            (example) => `
            {
                "snippet": "${example.snippet}",
                "isCorrect": ${example.isCorrect}
            },
        `,
        )}
        ]
    },
`,
    )
    .join('')}
]
`;

export const kodyRulesGeneratorDuplicateFilterSchema = z.object({
    uuids: z.array(z.string()),
});

export const prompt_KodyRulesGeneratorDuplicateFilterSystem = () => `
You will receive two lists of rules and guidelines with the following format:
[
    {
        "uuid": "55a0284b-eb7f-40ae-8b8c-db3dc66e8e0a",
        "title": "Avoid equality operators in loop termination conditions",
        "rule": "Check if loops use equality operators (== or !=) in termination conditions. These can lead to infinite loops if the condition is never met exactly. Instead, use relational operators like < or > for safer loop termination.",
        "severity": "Critical",
        "examples": [
            {
                "snippet": "for (var i = 1; i <= 10; i += 2)  // Compliant\n{\n  //...\n}",
                "isCorrect": false
            },
            {
                "snippet": "for (var i = 1; i != 10; i += 2)  // Noncompliant. Infinite; i goes from 9 straight to 11.\n{\n  //...\n}",
                "isCorrect": true
            }
        ]
    }
]

One of these lists will be rules that are already being used, the other will be rules that are new and have been generated.
You must look at the new rules and remove those which accomplish the same goal as a pre-existing rule. Meaning, there should be no duplicate rules in the final list.
The most important criteria for determining if a rule is a duplicate is the 'rule' field, if the 'rule' field are similar or the same, then the rules are duplicates.
The existing rules list may be empty, in which case you must keep all the new rules.

You must then output the list of rules uuids that have passed the filter in the following format:

{
    "uuids": [
        "uuid1",
        "uuid2",
        "uuid3"
    ]
}

Your output must be surrounded by \`\`\`json\`\`\` tags.
`;

export const prompt_KodyRulesGeneratorDuplicateFilterUser = (payload: {
    existingRules: LibraryKodyRule[];
    newRules: Array<Partial<IKodyRule>>;
}) => `
existing rules:

[
${payload.existingRules
    .map(
        (rule) => `
    {
        "uuid": "${rule?.uuid ?? ''}",
        "title": "${rule?.title ?? ''}",
        "rule": "${rule?.rule ?? ''}",
        ${rule?.why_is_this_important ? `"why_is_this_important": "${rule.why_is_this_important}",` : ''}
        "severity": "${rule?.severity ?? ''}",
        "tags": "${rule?.tags ?? ''}",
        "examples": [
        ${rule?.examples?.map(
            (example) => `
            {
                "snippet": "${example?.snippet ?? ''}",
                "isCorrect": ${example?.isCorrect ?? false}
            },
        `,
        )}
        ]
    },
`,
    )
    .join('')}
]

new rules:

[
${payload.newRules
    .map(
        (rule) => `
    {
        ${rule.uuid ? `"uuid": "${rule.uuid}",` : ''}
        "title": "${rule.title}",
        "rule": "${rule.rule}",
        "severity": "${rule.severity}",
        "examples": [
        ${rule.examples.map(
            (example) => `
            {
                "snippet": "${example.snippet}",
                "isCorrect": ${example.isCorrect}
            },
        `,
        )}
        ]
    },
`,
    )
    .join('')}
]
`;

export const kodyRulesGeneratorQualityFilterSchema = z.object({
    uuids: z.array(z.string()),
});

export const prompt_KodyRulesGeneratorQualityFilterSystem = () => `
You will receive a list of rules and guidelines with the following format:
[
    {
        "uuid": "55a0284b-eb7f-40ae-8b8c-db3dc66e8e0a",
        "title": "Avoid equality operators in loop termination conditions",
        "rule": "Check if loops use equality operators (== or !=) in termination conditions. These can lead to infinite loops if the condition is never met exactly. Instead, use relational operators like < or > for safer loop termination.",
        "severity": "Critical",
        "examples": [
            {
                "snippet": "for (var i = 1; i <= 10; i += 2)  // Compliant\n{\n  //...\n}",
                "isCorrect": false
            },
            {
                "snippet": "for (var i = 1; i != 10; i += 2)  // Noncompliant. Infinite; i goes from 9 straight to 11.\n{\n  //...\n}",
                "isCorrect": true
            }
        ]
    }
]

You must filter the list of rules and guidelines and remove those that are not of high quality.
A rule is considered of high quality if it is clear, concise, impactful and easy to understand.
Rules must be impactful and not too broad, they should be actionable and specific, they should not be general programming rules, best practices or meta rules.
For example, rules like 'use async await instead of Promises' are actionable and specific, while rules like 'use good variable names' are too broad and general.
You must remove all rules that are not of high quality.

You must then output the list of rules uuids that have passed the filter in the following format:

{
    "uuids": [
        "uuid1",
        "uuid2",
        "uuid3"
    ]
}

Your output must be surrounded by \`\`\`json\`\`\` tags.
`;

export const prompt_KodyRulesGeneratorQualityFilterUser = (payload: {
    rules: Array<Partial<IKodyRule>>;
}) => `
rules:

[
${payload.rules
    .map(
        (rule) => `
    {
        ${rule.uuid ? `"uuid": "${rule.uuid}",` : ''}
        "title": "${rule?.title ?? ''}",
        "rule": "${rule?.rule ?? ''}",
        "severity": "${rule?.severity ?? ''}",
        "examples": [
        ${rule?.examples?.map(
            (example) => `
            {
                "snippet": "${example?.snippet ?? ''}",
                "isCorrect": ${example?.isCorrect ?? false}
            },
        `,
        )}
        ]
    },
`,
    )
    .join('')}
]
`;
